package com.uw.uwregistry.controller;


import com.uw.uwregistry.cluster.Cluster;
import com.uw.uwregistry.exception.RegistryException;
import com.uw.uwregistry.meta.InstanceMeta;
import com.uw.uwregistry.meta.ServerMeta;
import com.uw.uwregistry.service.RegistryContainer;
import com.uw.uwregistry.service.RegistryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;


@Slf4j
@RestController
@RequiredArgsConstructor
public class UWRegistryController {

    private final RegistryService registryService;
    private final Cluster cluster;

    @RequestMapping("/register")
    public InstanceMeta register(@RequestParam String service, @RequestBody InstanceMeta instance) {
        log.info(" ===> register {} @ {}", service, instance);
        checkLeader();
        return registryService.register(service, instance);
    }

    @RequestMapping("/unregister")
    public InstanceMeta unregister(@RequestParam String service, @RequestBody InstanceMeta instance) {
        log.info(" ===> unregister {} @ {}", service, instance);
        checkLeader();
        return registryService.unregister(service, instance);
    }


    @RequestMapping("/fetchAll")
    public List<InstanceMeta> fetchAll(@RequestParam String service) {
        log.info(" ===> fetchAll {}", service);
        return registryService.fetchAll(service);
    }

    private void checkLeader() {
        if (!cluster.self().isLeader()) {
            throw new RegistryException("not leader");
        }
    }


    @RequestMapping("/heartbeat")
    public long heartbeat(@RequestParam String service, @RequestBody InstanceMeta instance) {
        log.info(" ===> heartbeat {} @ {}", service, instance);
        return registryService.heartbeat(instance, service);
    }

    @RequestMapping("/heartbeats")
    public long heartbeats(@RequestParam String services, @RequestBody InstanceMeta instance) {
        log.info(" ===> heartbeat {} @ {}", services, instance);
        return registryService.heartbeat(instance, services.split(","));
    }

    @RequestMapping("/versions")
    public Map<String, Long> versions(@RequestParam String services) {
        log.info(" ===> versions {}", services);
        return registryService.version(services.split(","));
    }

    @RequestMapping("/version")
    public Long version(@RequestParam String service) {
        log.info(" ===> versions {}", service);
        return registryService.version(service).getOrDefault(service, -1L);
    }

    @RequestMapping("/info")
    public ServerMeta info() {
        return cluster.self();
    }


    @RequestMapping("/cluster")
    public List<ServerMeta> cluster() {
        return cluster.getNodeList();
    }

    @RequestMapping("/snapshot")
    public RegistryContainer.Snapshot snapshot() {
        return RegistryContainer.snapshot();
    }

}
